import { Cls } from "./Defined";

/**
 * 对象池对象接口
 */
export interface IPoolObj {
	/**
	 * 当从对象池中取出时触发
	 * 在此进行初始化操作
	 */
	onAlloc(...args: any[]): any;

	/**
	 * 当回收进对象池里时触发
	 * 在此进行清理操作
	 */
	onFree(): void;
}

/**
 * 对象池
 */
export class Pool<T extends IPoolObj> {
	protected _objs: T[] = [];

	constructor(
		/** 对象的类 */
		readonly cls: Cls<T>,
		/** new时传入的参数 */
		public createArgs: any[] = [],
		/** 最大容量 */
		public max: number = Number.MAX_VALUE
	) {
		if (!this.createArgs) {
			this.createArgs = [];
		}
	}

	/** 当前池里的对象数量 */
	get count() {
		return this._objs.length;
	}

	/**
	 * 从池里获取一个对象，没有则创建
	 */
	alloc() {
		const item = this._objs.pop() || new this.cls(...this.createArgs);
		item.onAlloc();
		return item;
	}

	/**
	 * 从池里获取一个对象并传入参数，没有则创建
	 */
	allocArgs(...args: any[]) {
		const item = this._objs.pop() || new this.cls(...this.createArgs);
		item.onAlloc(...args);
		return item;
	}

	/**
	 * 回收对象
	 * @param obj
	 */
	free(obj: T) {
		obj.onFree();
		if (this.count < this.max) {
			this._objs.push(obj);
		}
	}

	/**
	 * 移除对象池里所有对象
	 */
	clear() {
		this._objs.length = 0;
	}
}

/**
 * 引用计数对象池对象接口
 */
export interface IRefPoolObj extends IPoolObj {
	/** 引用计数 */
	ref: number;
}

/**
 * 引用计数对象池
 */
export class RefPool<T extends IRefPoolObj> extends Pool<T> {
	alloc() {
		const obj = super.alloc();
		obj.ref = 1;
		return obj;
	}

	/**
	 * 回收对象
	 * 每次调用减少一次引用计数
	 * 当引用计数为0时才会真正回收
	 * @param obj
	 */
	free(obj: T) {
		if (--obj.ref <= 0) {
			super.free(obj);
		}
	}

	/**
	 * 忽略引用计数强制回收对象
	 * @param obj
	 */
	freeForce(obj: T) {
		super.free(obj);
	}
}
